package com.winner.jdk_dynamic_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

//ioc 完了以后,也就生成了代理类了.  spring什么时候生成代理类
// 同一个类中无事务方法调用同一个类的有事务方法问题原因及其解决方法
// 在xxxServiceImpl中，用(xxxService)(AopContext.currentProxy())，获取到xxxService的代理类，再调用事务方法
// https://blog.csdn.net/liuguang212/article/details/104695253?utm_medium=distribute.pc_feed_404.none-task-blog-2~default~BlogCommendFromBaidu~Rate-6.control404&depth_1-utm_source=distribute.pc_feed_404.none-task-blog-2~default~BlogCommendFromBaidu~Rate-6.control40

// https://www.jianshu.com/p/4df6e4d7eb46


//代理设计模式
//        1.静态代理是对类的代理      对被代理类的功能的扩展
//        概念: 静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起implements相同的接口或者是extends相同父类
//        有点: 可以做到在不修改目标对象的功能前提下,对目标功能扩展.
//        优缺点: 代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.

//动态代理是对接口的代理  动态代理在运行时生成代理类, 而静态代理,在编译时就有了.
//JDK动态代理步骤：
//        1.创建一个实现接口InvocationHandler的类，它必须重写invoke方法
//        2.创建被代理的类以及接口
//        3.通过Proxy的静态方法
//        newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
//        4.通过代理调用方法

//        CGLIB底层使用了ASM（一个短小精悍的字节码操作框架）来操作字节码生成新的类
//
//        攻心的子乐 8:47:55
//        CGLIB和Java动态代理的区别
//        Java动态代理只能够对接口进行代理，不能对普通的类进行代理（因为所有生成的代理类的父类为Proxy，Java类继承机制不允许多重继承）；CGLIB能够代理普通类；
//        Java动态代理使用Java原生的反射API进行操作，在生成类上比较高效；CGLIB使用ASM框架直接对字节码进行操作，在类的执行过程中比较高效



/**
 * 调用处理器实现类（有木有感觉这里就是传说中的AOP啊）
 * 每次生成动态代理类对象的时候都需要指定一个实现了该接口的调用处理器类
 * 参看链接如下
 * https://blog.csdn.net/hefenglian/article/details/81194569?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1.pc_relevant_paycolumn_v3&utm_relevant_index=1
 */
public class MyInvocationHandler implements InvocationHandler{
    /**
     * 我们要代理的真实对象
     */
    private Object realSubject;//为了new InvocationHandlerImpl(realSubject);传参名一致

    /**
     * 构造函数，为真实对象赋初值
     */
    public MyInvocationHandler(Object realSubject){
        this.realSubject =realSubject;
    }
    /**
     * invoke方法负责处理动态代理类中所有方法调用
     * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在代理真实对象前可以添加额外操作
        System.out.println("在用代理对象调用真实对象的方法#之前#，类似AOP的Before()，添加自己的操作");
        System.out.println("其调用的方法Method:"+method);  // method.getName() 打印代理对象调用的方法

        //当代理对象调用真实对象的方法时，其会自动跳转到代理对象关联的handler对象的invoke方法来进行调用
        Object returnValue=method.invoke(realSubject,args); // 该行代码 之前 之后, 对被代理类的功能进行扩展.

        //在代理对象调用真实对象的方法之后可以添加自己的操作
        System.out.println("在代理对象调用真实对象的方法#之后#,添加自己的操作");

        return returnValue;
    }
}
